<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>头像裁剪案例</title>
    <style>
        html,
        body {
            margin: 5px;
            padding: 0;
        }
    </style>
</head>

<body>
    <div style="width: 500px;height: 500px;border: 1px solid black;position: relative;float: left;">
        <canvas id="background" width="500" height="500" style="position: absolute;">
            浏览器不支持Canvas……
        </canvas>
        <canvas id="selector" width="500" height="500" style="position: absolute;">
            浏览器不支持Canvas……
        </canvas>
    </div>
    <div style="float: left;">
        <canvas width="500" height="500" id="preview"></canvas>
    </div>
    <div style="clear: both;float: left;">
        <input type="file" id="file">
    </div>
    <script>
    var backgroundCanvas = document.getElementById('background');
    var selectorCanvas = document.getElementById('selector');
    var previewCanvas = document.getElementById('preview');

    function buildBackground(cvs) {
        var ctx = cvs.getContext('2d');

        // 文件上传控件
        var fileInput = document.getElementById('file');

        // 用户选择文件之后，会发生change事件，监听这个事件
        fileInput.addEventListener('change', function () {

            var imageFile = fileInput.files[0];

            // 用于把file对象转换成一个当前页面里可以使用的url。记住就行。
            var url = URL.createObjectURL(imageFile);

            var img = new Image();
            img.src = url;
            img.addEventListener('load', function () {
                // 图像加载之后执行：使图像正好占满屏幕又不改变缩放的大小
                var w = img.width;
                var h = img.height;
                var scaleX = 500 / w;
                var scaleY = 500 / h;
                var scale = scaleX < scaleY ? scaleX : scaleY;

                ctx.save();
                ctx.translate(250, 250);
                ctx.scale(scale, scale); // 对坐标系进行缩放
                ctx.drawImage(img, -w / 2, -h / 2);

                ctx.restore();
            })
        });

    }
    buildBackground(backgroundCanvas);

    function buildSelector(cvs, backgroundCanvas, previewCanvas, previewFn) {
        var ctx = cvs.getContext('2d');

        var rect = {
            x: 50,
            y: 50,
            l: 100,
            draw: function () {
                ctx.clearRect(0, 0, 500, 500);
                ctx.fillStyle = 'rgba(0,0,0,0.5)';
                ctx.fillRect(0, 0, 500, 500);
                ctx.clearRect(this.x, this.y, this.l, this.l);
            }
        };

        var state = "闲置";
        var clickPoint = {};
        cvs.addEventListener('mousedown', function (evt) {
            var mx = evt.offsetX;
            var my = evt.offsetY;

            if (state == '闲置') {
                rect.x = mx;
                rect.y = my;
                state = "选择中"
            } else if (state == '已选择') {
                ctx.beginPath();
                ctx.rect(rect.x, rect.y, rect.l, rect.l);
                if (ctx.isPointInPath(mx, my)) {
                    clickPoint.x = mx;
                    clickPoint.y = my;
                    state = '拖动中'
                } else {
                    state = '闲置';
                    ctx.clearRect(0, 0, 500, 500);
                }
            }

        });


        cvs.addEventListener('mousemove', function (evt) {
            var mx = evt.offsetX;
            var my = evt.offsetY;

            if (evt.which == 1) {
                if (state == "选择中") {
                    var dx = mx - rect.x;
                    var dy = my - rect.y;
                    var l = dx > dy ? dx : dy;
                    rect.l = l;
                    rect.draw();
                } else if (state == '拖动中') {
                    var dx = mx - clickPoint.x;
                    var dy = my - clickPoint.y;
                    rect.x = rect.x + dx;
                    rect.y = rect.y + dy;
                    rect.draw();
                    clickPoint.x = mx;
                    clickPoint.y = my;
                }
            }
        });

        cvs.addEventListener('mouseup', function (evt) {
            var mx = evt.offsetX;
            var my = evt.offsetY;
            if (state == '选择中') {
                state = '已选择';
                previewFn(rect.x, rect.y, rect.l, rect.l, backgroundCanvas, previewCanvas);
            } else if (state == '拖动中') {
                state = '已选择';
                previewFn(rect.x, rect.y, rect.l, rect.l, backgroundCanvas, previewCanvas);

            }
        });


    }
    buildSelector(selectorCanvas, backgroundCanvas, previewCanvas, preview);

    function preview(x, y, w, h, backgroundCanvas, previewCanvas) {
        var ctx = previewCanvas.getContext('2d');
        ctx.drawImage(backgroundCanvas,
                x, y, w, h,
                0, 0, 500, 500
        )
    }

</script>
</body>

</html>